home *** CD-ROM | disk | FTP | other *** search
- /*========================= MiscCoordConverter.m ============================*/
- /* MiscCoordConverter is an abstract super class that supports the writing of
- converters between coordinate systems. All values are double precision
- floating point numbers representing locations in a three dimensional
- coordinate system.
-
- DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights
- Reserved. For further information on terms and conditions see
- the MiscKit license.
-
- HISTORY
- 10-Mar-93 Dale Amon at GPL
- Created.
- */
-
- #import <misckit/miscgiskit.h>
-
- @implementation MiscCoordConverter
-
- /*===========================================================================*/
- /* Internal Class Subcontractor support methods */
- /*===========================================================================*/
- /* register a converter to the list of conversion subcontractors */
-
- static id subcontractors = nil; /* Master list of converters */
-
- + registerSubcontractor: aConverter
- { if (!subcontractors)
- subcontractors = [[List allocFromZone:[self zone]] init];
- [subcontractors addObjectIfAbsent: aConverter];
- return self;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* unregister a converter from the list of conversion subcontractors */
-
- + unregisterSubcontractor: aConverter
- { [subcontractors removeObject:aConverter];
- return self;
- }
-
- /*---------------------------------------------------------------------------*/
- /* get the name of the next one in the list */
-
- + getSubcontractor:(unsigned int) n {return [subcontractors objectAt:n];}
-
-
- /*===========================================================================*/
- /* General Class methods */
- /*===========================================================================*/
- /* Initialize the class */
-
- + initialize
- {[MiscCoordConverter setVersion:MISC_COORD_CONVERTER_VERSION_ID]; return self;}
-
-
- /*===========================================================================*/
- /* Initialization methods */
- /*===========================================================================*/
- /* We cache everything that we will need repeatedly, ie the class id's
- of all the MiscCoord classes we know how to service.
-
- Every instance of a converter is registered so it can be subcontracted
- to.
-
- */
-
- - init
- { [MiscCoordConverter registerSubcontractor: self];
- return self;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* Free self and subcontractor list, but NOT the subcontractors.
-
- There is a potential problem: what if someone holds
- a pointer to us? Some going out of business notification
- would be necessary in that case.
-
- Most subclasses lock out free so this is not an immediate problem
- */
-
- - free
- { [MiscCoordConverter unregisterSubcontractor:self];
- [services free];
- return [self free];
- }
-
-
- /*===========================================================================*/
- /* Service support methods */
- /*===========================================================================*/
- /* For subclass use: add a service to our list of conversion services. */
-
- - addService: (SEL) aSelector convertsFrom: (Class) one to: (Class) two
- { struct __MiscService theService;
-
- if (!services)
- services = [[Storage allocFromZone:[self zone]]
- initCount: 0
- elementSize: MISC_SERVICE_SIZE
- description: MISC_SERVICE_DESCRIPTION];
-
- theService.iClass = one;
- theService.oClass = two;
- theService.xlator = aSelector;
- [services addElement: (void*) &theService];
- return self;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* Internal method to search for a service in our list of conversion services.
- We return the selector that can carry out the desired conversion,
- or else a null selector if we cannot. It is assumed that a null selector
- will always be undefined.
-
- */
-
- - (SEL) findServiceFrom: (Class) one to: (Class) two
- { struct __MiscService *theService;
-
- unsigned int i, cnt = [services count];
-
- for (i=0; i<cnt; i++)
- { theService = (struct __MiscService *) [services elementAt:i];
- if ((theService->iClass == one) &&
- (theService->oClass == two)) return theService->xlator;
- }
- return (SEL) 0;
- }
-
- /*===========================================================================*/
- /* Basic conversion methods (Internal use only) */
- /*===========================================================================*/
- /* Collect info we need to carry out the requested job
-
- NOTE: Any method that is sent to srcCoord or dstCoord must be in
- the MiscCoordConverterClient protocol!
- */
-
- - prepareForJob: inCoord : outCoord
- {
- srcConstants = [inCoord constants];
- dstConstants = [outCoord constants];
- sameConstants = [srcConstants isEqual: dstConstants];
-
- dimensions = [[inCoord class] dimensions];
- npoints = [inCoord curBlockSize];
-
- src = [inCoord curPtr];
- dst = [outCoord curPtr];
-
- return self;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* a quick means of copying if data formats are identical. This method
- is known outside by name, but should never be actually used outside
- of applyTransform.
-
- It will fail if the constants associated with the two MiscCoords are not
- functionally the same.
-
- */
-
- - (BOOL) copyCoords
- { int len;
-
- if (!sameConstants) return NO;
- len = dimensions * npoints * sizeof(double);
- bcopy((char*)src, (char*)dst, len);
-
- return YES;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* Apply the specified method to a block of coordinates. Job is set up
- by prepareForJob: before this method is called.
- */
-
- - (BOOL) applyTransform:(SEL)aSelector
- { unsigned int i;
-
- /* copy has it's own loop */
- if (aSelector == @selector(copyCoords))
- [self perform: aSelector];
- else
- for (i=0;
- i<npoints;
- i++,dst+=dimensions,src+=dimensions)
- [self perform: aSelector];
-
- return YES;
- }
-
-
- /*---------------------------------------------------------------------------*/
- /* Conversion setup method. This method sees if we or anyone we know of
- can handle the requested job. If so, we return YES with local instance
- vars theTransform and subContractor ready to go.
-
- NOTE: If you want to handle conversion between coords of different
- dimensionality, look here first.
-
- Both MiscCoords must:
- 1) Conform to the MiscCoordConverterClient protocol.
- 2) Have the same dimensionality.
- 3) Have the same transfer blocksize pre-set to the same size.
- 4) Some Converter object must be willing to accept the job
- of converting or copying between the two types.
-
- */
-
- - (BOOL) reviewSpecification: inCoord to: outCoord
- { unsigned int i;
- Class srcClass, dstClass;
- BOOL srcOk,dstOk;
-
- srcClass = [inCoord class];
- dstClass = [outCoord class];
- srcOk = [srcClass conformsTo:@protocol(MiscCoordConverterClient)];
- dstOk = [dstClass conformsTo:@protocol(MiscCoordConverterClient)];
- if (!(srcOk && dstOk)) return NO;
-
- if ([srcClass dimensions] != [dstClass dimensions]) return NO;
- if ([inCoord curBlockSize] != [outCoord curBlockSize]) return NO;
-
- /* We should be able to handle it ourselves most of the time, or
- else the customer has the wrong delegate! */
-
- if (theTransform = [self findServiceFrom: srcClass to: dstClass])
- aSubcontractor = self;
- else
- /* If we can't do it ourselves, try subcontracting to one of the
- other registered convertors
- */
- for (i=0; aSubcontractor = [MiscCoordConverter getSubcontractor:i]; i++)
- {if (aSubcontractor == self) continue;
- if (theTransform =
- [aSubcontractor findServiceFrom: srcClass to: dstClass])
- break;
- }
-
- return ((theTransform) ? YES : NO);
- }
-
-
- /*===========================================================================*/
- /* Misc Coord Converter Server protocol */
- /*===========================================================================*/
- /* Convert the specified block of coordinates from the source type to the
- destination type if we are able, or if we can subcontract it to someone
- else who is able to do it. If there is any reason at all that we
- cannot, then return NO.
-
- DESIGN NOTE: Although local methods are executing, there may be one OR two
- different objects with private storage involved. Care must be taken to
- make sure that setup takes place in the correct object, ie usually the
- subcontractor object. The subcontractor will often be self, in which case
- setting ivars in this method would work: but if not, the subcontractor
- would probably crash because things would not be set up in ITS' ivars.
- THINK before making changes to where set up occurs!
-
- */
-
- - (BOOL) convert: inCoord to: outCoord
- {
- if (![self reviewSpecification: inCoord to: outCoord]) return NO;
- [aSubcontractor prepareForJob: inCoord : outCoord];
- return [aSubcontractor applyTransform:theTransform];
- }
-
-
- /*===========================================================================*/
- /* For Subclass use: We have a fast means of copying, but there is no need to
- make it really public. To discourage possibly disastrous attempts to use it
- directly, we supply a means of getting it's selector for use in an
- addService method by a subclass.
- */
-
- - (SEL) fastCopySelector {return (@selector(copyCoords));}
-
-
- /*===========================================================================*/
- /* Archive methods */
- /*===========================================================================*/
- /* This class should not be used on its own. Presumably a subclass will
- re-generate it's services list when it awakes, or if it is a single
- instance class, it will just delete this object when it answers with
- a finishUnarchiving message.
- */
-
- - awake
- { [super awake];
-
- services = nil;
- [MiscCoordConverter registerSubcontractor: self];
- return self;
- }
-
- @end
-